import io
from io import BytesIO
from pipes import quote

import xlwt
from django.http import JsonResponse, HttpRequest, HttpResponse
from django.shortcuts import render, redirect
from django.views.decorators.cache import cache_page
from reportlab.pdfgen import canvas
from rest_framework.decorators import api_view
from rest_framework.response import Response

from polls.mappers import SubjectMapper, TeacherMapper, SubjectSimpleMapper
from polls.models import Subject, Teacher, User
from polls.serializers import SubjectSerializer, SubjectSimpleSerializer, TeacherSerializer
from polls.utils import gen_random_code, Captcha, gen_md5_digest


def index(request):
    """首页"""
    return redirect('/static/html/subjects.html')


# def show_subjects(request):
#     # subjects = Subject.objects.all().order_by('no')
#     queryset = Subject.objects.all()
#     subjects = [SubjectMapper(subject).as_dict() for subject in queryset]
#     # return render(request, 'subjects.html', {'subjects': subjects})
#     return JsonResponse(subjects, safe=False)


# def show_teachers(request):
#     try:
#         sno = int(request.GET.get('sno'))
#         teachers = []
#         if sno:
#             subject = Subject.objects.only('name').get(no=sno)
#             teachers = Teacher.objects.filter(subject=subject).order_by('no')
#         return render(request, 'teachers.html', {
#             'subject': subject,
#             'teachers': teachers
#         })
#     except (ValueError, Subject.DoesNotExist):
#         return redirect('/')

# def show_teachers(request):
#     """获取指定学科的老师"""
#     try:
#         sno = request.GET['sno']
#         subject = Subject.objects.get(no=sno)
#         queryset = Teacher.objects \
#             .filter(subject__no=sno).defer('subject')
#         teachers = [TeacherMapper(teacher).as_dict()
#                     for teacher in queryset]
#         data = {
#             'code': 20000,
#             'subject': SubjectSimpleMapper(subject).as_dict(),
#             'teachers': teachers
#         }
#     except (KeyError, ValueError, Subject.DoesNotExist):
#         data = {'code': 20001, 'message': '请求老师数据失败'}
#     return JsonResponse(data)


# def praise_or_criticize(request):
#     """好评"""
#     try:
#         tno = int(request.GET.get('tno'))
#         teacher = Teacher.objects.get(no=tno)
#         if request.path.startswith('/praise'):
#             teacher.good_count += 1
#             count = teacher.good_count
#         else:
#             teacher.bad_count += 1
#             count = teacher.bad_count
#         teacher.save()
#         data = {'code': 20000, 'mesg': '操作成功', 'count': count}
#     except (ValueError, Teacher.DoseNotExist):
#         data = {'code': 20001, 'mesg': '操作失败'}
#     return JsonResponse(data)

def praise_or_criticize(request: HttpRequest) -> HttpResponse:
    if request.session.get('userid'):
        try:
            tno = int(request.GET.get('tno'))
            teacher = Teacher.objects.get(no=tno)
            if request.path.startswith('/praise/'):
                teacher.good_count += 1
                count = teacher.good_count
            else:
                teacher.bad_count += 1
                count = teacher.bad_count
            teacher.save()
            data = {'code': 20000, 'mesg': '投票成功', 'count': count}
        except (ValueError, Teacher.DoesNotExist):
            data = {'code': 20001, 'mesg': '投票失败'}
    else:
        data = {'code': 20002, 'mesg': '请先登录'}
    return JsonResponse(data)


# def login(request: HttpRequest) -> HttpResponse:
#     """登录"""
#     hint = ''
#     return render(request, 'login.html', {'hint': hint})

def login(request: HttpRequest) -> HttpResponse:
    hint = ''
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username and password:
            password = gen_md5_digest(password)
            user = User.objects.filter(username=username, password=password).first()
            if user:
                request.session['userid'] = user.no
                request.session['username'] = user.username
                return redirect('/')
            else:
                hint = '用户名或密码错误'
        else:
            hint = '请输入有效的用户名和密码'
    return render(request, 'login.html', {'hint': hint})


def logout(request):
    """注销"""
    request.session.flush()
    return redirect('/')


def get_captcha(request: HttpRequest) -> HttpResponse:
    """验证码"""
    captcha_text = gen_random_code()
    print(f'captcha_text: {captcha_text}')
    request.session['captcha'] = captcha_text
    image_data = Captcha.instance().generate(captcha_text)
    return HttpResponse(image_data, content_type='image/png')


def export_teachers_excel(request):
    # 创建工作簿
    wb = xlwt.Workbook()
    # 添加工作表
    sheet = wb.add_sheet('老师信息表')
    # 查询所有老师的信息
    # queryset = Teacher.objects.all()
    queryset = Teacher.objects.all().select_related('subject')
    # 向Excel表单中写入表头
    colnames = ('姓名', '介绍', '好评数', '差评数', '学科')
    for index, name in enumerate(colnames):
        sheet.write(0, index, name)
    # 向单元格中写入老师的数据
    props = ('name', 'detail', 'good_count', 'bad_count', 'subject')
    for row, teacher in enumerate(queryset):
        for col, prop in enumerate(props):
            value = getattr(teacher, prop, '')
            if isinstance(value, Subject):
                value = value.name
            sheet.write(row + 1, col, value)
    # 保存Excel
    buffer = BytesIO()
    wb.save(buffer)
    # 将二进制数据写入响应的消息体中并设置MIME类型
    resp = HttpResponse(buffer.getvalue(), content_type='application/vnd.ms-excel')
    # 中文文件名需要处理成百分号编码
    filename = quote('老师.xls')
    # 通过响应头告知浏览器下载该文件以及对应的文件名
    resp['content-disposition'] = f'attachment; filename*=utf-8\'\'{filename}'
    return resp


def export_pdf(request: HttpRequest) -> HttpResponse:
    buffer = io.BytesIO()
    pdf = canvas.Canvas(buffer)
    pdf.setFont("Helvetica", 80)
    pdf.setFillColorRGB(0.2, 0.5, 0.3)
    pdf.drawString(100, 550, 'hello, world!')
    pdf.showPage()
    pdf.save()
    resp = HttpResponse(buffer.getvalue(), content_type='application/pdf')
    resp['content-disposition'] = 'inline; filename="demo.pdf"'
    return resp


"""
总结
当Content-Disposition设置为attachment时，浏览器会提示用户下载文件。
当Content-Disposition设置为inline时，浏览器会尝试直接在当前窗口中打开文件。
"""


def go_echarts(request):
    return render(request, 'echarts_teacher.html', {})


def get_teachers_data(request):
    queryset = Teacher.objects.all()
    names = [teacher.name for teacher in queryset]
    good_counts = [teacher.good_count for teacher in queryset]
    bad_counts = [teacher.bad_count for teacher in queryset]
    return JsonResponse({'names': names, 'good': good_counts, 'bad': bad_counts})
    # return render(request, 'echarts_teacher.html', {
    #     # 'names': names,
    #     # 'good_counts': good_counts,
    #     # 'bad_counts': bad_counts
    #     'json': {'names': names, 'good': good_counts, 'bad': bad_counts}
    # })


@api_view(('GET',))
@cache_page(timeout=86400, cache='default')
def show_subjects(request: HttpRequest) -> HttpResponse:
    subjects = Subject.objects.all().order_by('no')
    # 创建序列化器对象并指定要序列化的模型
    serializer = SubjectSerializer(subjects, many=True)
    # 通过序列化器的data属性获得模型对应的字典并通过创建Response对象返回JSON格式的数据
    return Response(serializer.data)


@api_view(('GET',))
def show_teachers(request: HttpRequest) -> HttpResponse:
    try:
        sno = request.GET.get('sno')
        print(f'sno: {sno}')
        if sno is None:
            teachers = Teacher.objects.all()
            serializer = TeacherSerializer(teachers, many=True)
            return Response(serializer.data)
        else:
            subject = Subject.objects.only('name').get(no=int(sno))
            teachers = Teacher.objects.filter(subject=subject).defer('subject').order_by('no')
            subject_seri = SubjectSimpleSerializer(subject)
            teacher_seri = TeacherSerializer(teachers, many=True)
            return Response({'subject': subject_seri.data, 'teachers': teacher_seri.data})
    except (TypeError, ValueError, Subject.DoesNotExist):
        return Response(status=404)
